package com.shawn.server.service;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.api.R;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.shawn.autoconfig.template.FaceIdTemplate;
import com.shawn.autoconfig.template.OssTemplate;
import com.shawn.autoconfig.template.SmsTemplate;
import com.shawn.commons.utils.DateUtils;
import com.shawn.dubbo.api.*;
import com.shawn.model.entity.*;
import com.shawn.model.mongo.RecommendUser;
import com.shawn.model.mongo.UserLike;
import com.shawn.model.vo.*;
import com.shawn.server.exception.BusinessException;
import com.shawn.server.interceptor.ThreadContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class UserInfoService {
    @DubboReference
    private UserInfoApi userInfoApi;

    @DubboReference
    private SettingsApi settingsApi;

    @DubboReference
    private UserApi userApi;

    @DubboReference
    private QuestionApi questionApi;

    @DubboReference
    private BlackListApi blackListApi;

    @DubboReference
    private UserLikeApi userLikeApi;

    @DubboReference
    private RecommendUserApi recommendUserApi;

    @DubboReference
    private VisitorsApi visitorsApi;

    /**
     * 阿里云文件保存
     */
    @Autowired
    private OssTemplate ossTemplate;

    /**
     * 百度云人脸识别
     */
    @Autowired
    private FaceIdTemplate faceIdTemplate;


    @Autowired
    private SmsTemplate smsTemplate;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 得到朋友数量
     *
     * @param userId 用户id
     * @return {@link Map}<{@link String}, {@link Integer}>
     */
    public Map<String, Integer> getFriendsDetail(Long userId) {
        return userLikeApi.getFriendsDetailCount(userId);
    }

    @CacheEvict(value = "userInformation",key = "#id")
    public ResponseEntity updateHeadPhoto(MultipartFile headPhoto, Long id) throws IOException {
        //保存头像并获取路径
        String imageURL = ossTemplate.upLoading(Objects.requireNonNull(headPhoto.getOriginalFilename()), headPhoto.getInputStream());
        //下载图片,检测人脸
        boolean result = faceIdTemplate.faceCheck(imageURL);
        if (!result) {
            //检测不到人脸
            throw new BusinessException(ErrorResult.faceError());
        } else {
            //更新用户信息,将图片资源路径保存到数据库
            UserInfo userInfo = new UserInfo();
            userInfo.setId(id);
            userInfo.setAvatar(imageURL);
            userInfoApi.updateUserInfo(userInfo);
            return ResponseEntity.ok("null");
        }
    }

    public void saveUserInfo(UserInfo userInfo) throws ParseException {
        Integer age = DateUtils.countAge(userInfo.getBirthday());
        userInfo.setAge(age);
        userInfoApi.saveUserInfo(userInfo);
    }

    public UserInfoVo findDetailById(Long id) {
        UserInfo userInfo = userInfoApi.findDetailById(id);
        UserInfoVo userInfoVo = new UserInfoVo();
        //仅复制同名属性
        BeanUtils.copyProperties(userInfo, userInfoVo);
        //给不同类型属性复制
        if (userInfo.getAge() != null) {
            userInfoVo.setAge(userInfo.getAge().toString());
        }
        return userInfoVo;
    }
    @CacheEvict(value = "userInformation",key = "#userInfo.id")
    public void updateUserInfo(UserInfo userInfo) throws ParseException {
        Integer age = DateUtils.countAge(userInfo.getBirthday());
        userInfo.setAge(age);
        userInfoApi.updateUserInfo(userInfo);
    }

    public SettingsVo getSettings(Long userId) {
        SettingsVo settingsVo = new SettingsVo();
        //查询用户设置信息
        Settings settings = settingsApi.getSettingsByUserId(userId);
        Question question = questionApi.getQuestionByUserId(userId);
        if (settings == null) {
            //如果个人暂未进行设置,对齐设置进行初始化
            Settings defaultSettings = new Settings();
            //默认通知,初始化!
            defaultSettings.setGonggaoNotification(true);
            defaultSettings.setLikeNotification(true);
            defaultSettings.setPinglunNotification(true);
            defaultSettings.setUserId(userId);
            settingsApi.insertDefaultSettings(defaultSettings);
            BeanUtils.copyProperties(defaultSettings, settingsVo);
        } else {
            BeanUtils.copyProperties(settings, settingsVo);
        }
        if (question == null) {
            //如果问题暂未设置,对齐问题进行初始化
            Question defaultQuestion = new Question();
            defaultQuestion.setUserId(userId);
            questionApi.insertDefaultQuestion(defaultQuestion);
            settingsVo.setStrangerQuestion(defaultQuestion.getTxt());
        } else {
            settingsVo.setStrangerQuestion(question.getTxt());
        }
        //查询数据库
        User user = userApi.findById(ThreadContext.getUserId());
        settingsVo.setPhone(user.getMobile());
        return settingsVo;
    }

    public void updateQuestion(Long userId, String txt) {
        Question question = new Question();
        question.setUserId(userId);
        question.setTxt(txt);
        questionApi.updateByUserId(question);
    }

    public void updateSettings(Settings settings) {
        settingsApi.update(settings);
    }

    public ResponseEntity sendVerificationCode(String userPhone) {
        String findCode = redisTemplate.opsForValue().get("CHECK_CODE_" + userPhone);
        if (findCode != null) {
            return ResponseEntity.ok("验证码已发送");
        }
        //生成验证码
//        String code = RandomStringUtils.randomNumeric(6);
        String code = "111111";
        //将验证码存入redis,五分钟失效!
        redisTemplate.opsForValue().set("CHECK_CODE_" + userPhone, code, Duration.ofMinutes(5));

        //调用模板发送短信
//        String message = smsTemplate.sendShortMessage(phone, code);
        String message = "ok";

        log.info("短信验证码:{}已发送!", code);
        return ResponseEntity.ok(message);
    }

    public Boolean checkVerificationCode(String userPhone, String inputCode) {
        //获取redis缓存验证码
        String code = redisTemplate.opsForValue().get("CHECK_CODE_" + userPhone);
        Boolean res = !Strings.isEmpty(code) && code.equals(inputCode);
        if (res) {
            //清除缓存验证码
            redisTemplate.delete("CHECK_CODE_" + userPhone);
        }
        return res;
    }

    public PageResult<UserInfo> getBlackList(Integer page, Integer pageSize, Long userId) {
        //查询总记录数
        IPage<UserInfo> iPage = blackListApi.selectByPage(page, pageSize, userId);
        return new PageResult<>(page, pageSize, (int) iPage.getTotal(), iPage.getRecords());
    }

    public void removeBlackList(Long blackListId) {
        Long userId = ThreadContext.getUserId();
        blackListApi.removeById(userId, blackListId);
    }

    /**
     * 获取用户信息
     * 1 互相关注
     * 2 我关注
     * 3 粉丝
     * 4 谁看过我
     *
     * @param page     页面
     * @param pageSize 页面大小
     * @param nickname 昵称
     * @param type     类型
     * @return {@link PageResult}<{@link RelationUserInfoVo}>
     */
    public PageResult<RelationUserInfoVo> getUserInfo(Integer page, Integer pageSize, String nickname, Integer type) {
        Long userId = ThreadContext.getUserId();
        List<UserLike> likes = new ArrayList<>();
        boolean res ;
        Map<Long, UserLike> likeIdMap = new HashMap<>();
        List<Long> likeIds =new ArrayList<>() ;
        List<Long> ids = new ArrayList<>();
        if (type==4){
            //返回访问者详细列表
            ids = visitorsApi.getAllVisitors(userId);
           if (ids.isEmpty()){
               return new PageResult<>();
           }
           //获取上述id访问者是否为当前用户喜欢
             likes = userLikeApi.getFriendsDetail(userId,ids);
           //
            if (likes.size()!=0) {
                res = Objects.equals(likes.get(0).getUserId(), userId);
                likeIdMap = CollUtil.fieldValueMap(likes, res ? "likeUserId" : "userId");
                likeIds = likes.stream().map(res ? UserLike::getLikeUserId : UserLike::getUserId).collect(Collectors.toList());
            }
        }else {
             likes = userLikeApi.getFriendsDetail(userId, type);
            if (likes.size() == 0) {
                return new PageResult<>();
            }
             res = Objects.equals(likes.get(0).getUserId(), userId);
            likeIdMap = CollUtil.fieldValueMap(likes,res?"likeUserId":"userId");
             likeIds = likes.stream().map(res ? UserLike::getLikeUserId : UserLike::getUserId).collect(Collectors.toList());
        }

            //获取所有相关者详细信息
            UserInfo info = new UserInfo();
            info.setNickname(nickname);
            if (type==4){
                likeIds=ids;
            }
            //当type==4时,查询访客详细信息!
            PageResult<UserInfo> pageResult = userInfoApi.findByIds(likeIds, info, page, pageSize);
            if (pageResult.getCounts()==0){
                return new PageResult<>();
            }
            //获取当前用所有推荐者信息
            List<RecommendUser> recommendUsers = recommendUserApi.findAll(userId);
            Map<Long, RecommendUser> recMap = CollUtil.fieldValueMap(recommendUsers, "userId");

            //遍历所有相关者个人信息
            List<UserInfo> likesInfo = pageResult.getItems();
            ArrayList<RelationUserInfoVo> vos = new ArrayList<>();
            for (UserInfo ui : likesInfo) {
                RelationUserInfoVo vo = RelationUserInfoVo.init(ui, recMap.get(ui.getId()), likeIdMap.get(ui.getId()));
                vos.add(vo);
            }
            return new PageResult<>(page,pageSize,pageResult.getCounts(),vos);
    }
}
